<!-- ### Vue3全局Message组件实现方案 
 
#### 核心实现思路 
1. **组件动态挂载**：使用`createApp`动态创建组件实例 
2. **全局方法注入**：通过`app.config.globalProperties` 挂载全局方法 
3. **消息队列管理**：使用数组维护消息实例，实现自动位置计算 
4. **动画效果处理**：利用Vue的`Transition`组件实现滑入滑出动画 
 
---
 
#### 步骤1：创建基础组件  -->
<!-- src/components/Message/index.vue  -->
<template>
  <Transition name="message-fade">
    <div 
      v-if="visible"
      class="message-box"
      :class="[typeClass]"
      :style="{ top: localPosition + 'px' }"
    >
      <span class="icon">{{ typeIcon }}</span>
      <span class="content">{{ message }}</span>
    </div>
  </Transition>
</template>
 
<script setup>
import { ref, computed, onMounted } from 'vue'
 
const props = defineProps({
  type: {
    type: String,
    default: 'info',
    validator: (val) => ['success', 'warning', 'error', 'info'].includes(val)
  },
  message: {
    type: String,
    required: true 
  },
  duration: {
    type: Number,
    default: 3000 
  },
  _uid: {},
  position: {
    type: Number,
    default: 0
  }
})
 
const visible = ref(false)
const localPosition = ref(props.position)
defineExpose({
  localPosition
})
// 类型图标映射 
const typeIcon = computed(() => {
  const icons = {
    success: '✅',
    warning: '⚠️',
    error: '❌',
    info: '💡'
  }
  return icons[props.type]
})
 
// 类型样式类 
const typeClass = computed(() => `message-${props.type}`) 
 
// 自动关闭逻辑 
onMounted(() => {
  visible.value  = true 
  setTimeout(() => {
    visible.value  = false 
    setTimeout(() => {
      destroyInstance()
    }, 300)
  }, props.duration) 
})
 
// 销毁实例 
const destroyInstance = () => {
  const el = document.getElementById(props._uid)
  el?.parentNode?.removeChild(el)
}
</script>
 
<style scoped>
.message-box {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  min-width: 300px;
  padding: 12px 20px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  z-index: 9999;
  transition: all 0.3s ease;
}
 
.message-success {
  background: #f0f9eb;
  color: #67c23a;
  border: 1px solid #e1f3d8;
}
 
.message-warning {
  background: #fdf6ec;
  color: #e6a23c;
  border: 1px solid #faecd8;
}
 
.message-error {
  background: #fef0f0;
  color: #f56c6c;
  border: 1px solid #fde2e2;
}
 
.message-info {
  background: #edf2fc;
  color: #909399;
  border: 1px solid #ebeeff;
}
 
.icon {
  margin-right: 10px;
}
 
.message-fade-enter-from {
  opacity: 0;
  transform: translateY(-20px);
}
 
.message-fade-leave-to {
  opacity: 0;
  transform: translateY(-20px);
}
</style>